package net.seabookchen.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.seabookchen.dao.BlogCommentDao;
import net.seabookchen.dao.BlogPostDao;
import net.seabookchen.dao.BlogTagDao;
import net.seabookchen.pojo.BlogComment;
import net.seabookchen.pojo.BlogPost;
import net.seabookchen.pojo.BlogTag;
import net.seabookchen.pojo.wrapper.BlogPopularity;
import net.seabookchen.pojo.wrapper.BlogTagWrapper;

import org.datanucleus.util.StringUtils;

import com.google.appengine.api.datastore.EntityNotFoundException;
import com.googlecode.objectify.Key;

public class BlogService {
	private BlogPostDao postDao = null;
	private BlogCommentDao commentDao = null;
	private BlogTagDao tagDao = null;
	
	private List<BlogPopularity> popularBlogs = new ArrayList<BlogPopularity>();

	public BlogService() {
		if (postDao == null) {
			postDao = new BlogPostDao(BlogPost.class);
		}

		if (commentDao == null) {
			commentDao = new BlogCommentDao(BlogComment.class);
		}

		if (tagDao == null) {
			tagDao = new BlogTagDao(BlogTag.class);
		}
	}

	public void saveOrUpdateBlogEntry(BlogPost post) {

		if (post.getId() == null) {
			postDao.addPost(post);
			return;
		}

		BlogPost bPost = getOrCreatePost(post.getId());
		if (!StringUtils.isEmpty(post.getTitle()))
			bPost.setTitle(post.getTitle());
		if (!StringUtils.isEmpty(post.getContent()))
			bPost.setContent(post.getContent());
		if (!post.getTags().isEmpty()) {
			bPost.setTags(post.getTags());
		}
		bPost.setModifiedDate(new Date());
		postDao.put(bPost);
	}

	public void deleteBlogEntry(BlogPost post) {
		List<BlogComment> comments = commentDao.getAllCommentsByPost(post);
		commentDao.deleteAll(comments);
		postDao.delete(post);
	}

	public void deleteBlogEntry(Long postId) {
		BlogPost post = getOrCreatePost(postId);
		List<BlogComment> comments = commentDao.getAllCommentsByPost(post);
		commentDao.deleteAll(comments);
		postDao.deletePost(post);
	}

	public BlogPost getOrCreatePost(long id) {
		BlogPost post = null;
		try {
			post = postDao.get(id);
		} catch (EntityNotFoundException e) {
			post = new BlogPost();
			post.setId(id);
		}

		return post;
	}

	public BlogPost addThumbs(long id, boolean isThumbUp) {
		BlogPost bPost = getOrCreatePost(id);

		if (isThumbUp) {
			bPost.setThumbsUp(bPost.getThumbsUp() + 1);
		} else {
			bPost.setThumbsDown(bPost.getThumbsDown() + 1);
		}

		postDao.put(bPost);

		return bPost;
	}

	public BlogPost addComment2Post(Long id, BlogComment comment) {
		BlogPost bPost = getOrCreatePost(id);
		bPost.getComments().add(commentDao.put(comment));
		Key<BlogPost> key = postDao.put(bPost);
		comment.setPost(key);
		commentDao.put(comment);

		return bPost;
	}

	public BlogPost deleteCommentFromPost(Long postId, Long commentId) {
		BlogPost bPost = getOrCreatePost(postId);
		commentDao.delete(commentId);
		removeReleatedKeys((Collection) bPost.getComments(), commentId);
		postDao.put(bPost);
		return bPost;
	}

	public BlogPost deleteCommentFromPost(Long postId, BlogComment comment) {
		return deleteCommentFromPost(postId, comment.getId());
	}

	public BlogPost addTag2Post(Long id, BlogTag tag) {
		return addTag2Post(id, tag.getId());
	}

	public BlogPost addTag2Post(Long id, Long tagId) {
		BlogPost bPost = getOrCreatePost(id);
		Key<BlogTag> key = new Key<BlogTag>(BlogTag.class, tagId);
		bPost.getTags().add(key);
		postDao.put(bPost);
		return bPost;
	}

	public BlogPost addTags2Post(Long id, List<BlogTag> tags) {
		List<Long> tagIds = new ArrayList<Long>();
		for (BlogTag tag : tags) {
			tagIds.add(tag.getId());
		}
		return addTags2PostById(id, tagIds);
	}

	public BlogPost addTags2PostById(Long id, List<Long> tagIds) {
		BlogPost bPost = getOrCreatePost(id);
		for (Long tagId : tagIds) {
			Key<BlogTag> key = new Key<BlogTag>(BlogTag.class, tagId);
			bPost.getTags().add(key);
			postDao.put(bPost);
		}

		return bPost;
	}

	public BlogPost deleteTagFromPost(Long postId, Long tagId) {
		BlogPost bPost = getOrCreatePost(postId);
		removeReleatedKeys((Collection) bPost.getTags(), tagId);
		postDao.put(bPost);
		return bPost;
	}

	public BlogPost deleteTagFromPost(Long postId, BlogTag tag) {
		return deleteTagFromPost(postId, tag.getId());
	}

	public BlogPostDao getPostDao() {
		return postDao;
	}

	public void setPostDao(BlogPostDao postDao) {
		this.postDao = postDao;
	}

	public BlogCommentDao getCommentDao() {
		return commentDao;
	}

	public void setCommentDao(BlogCommentDao commentDao) {
		this.commentDao = commentDao;
	}

	public BlogTagDao getTagDao() {
		return tagDao;
	}

	public void setTagDao(BlogTagDao tagDao) {
		this.tagDao = tagDao;
	}

	private void removeReleatedKeys(Collection<Key> c, Long id) {
		Iterator<Key> iter = c.iterator();
		while (iter.hasNext()) {
			Key key = iter.next();
			if (key.getId() == id) {
				c.remove(key);
				break;
			}
		}
	}

	public Set<Key<BlogTag>> transferTagId2KeySet(String[] ids) {
		Set<Key<BlogTag>> set = new HashSet<Key<BlogTag>>();

		for (int i = 0; i < ids.length; i++) {
			long tagId = Long.valueOf(ids[i]);
			Key<BlogTag> key = new Key<BlogTag>(BlogTag.class, tagId);
			set.add(key);
		}

		return set;
	}
	
	public List<BlogTag> getTagsByPost(Set<Key<BlogTag>> keys) {
		List<BlogTag> tags = new ArrayList<BlogTag>();
		
		if (keys == null || keys.size() == 0) {
			return tags;
		}
		
		Map<Key<BlogTag>, BlogTag> tagMap = tagDao.ofy().get(keys);
		
		Collection<BlogTag> cTags =  tagMap.values();
		for (Iterator iterator = cTags.iterator(); iterator.hasNext();) {
			BlogTag blogTag = (BlogTag) iterator.next();
			tags.add(blogTag);
		}
		
		return tags;
	}
	
	public List<BlogTag> getTagsByPost(BlogPost post) {
		Set<Key<BlogTag>> keys = post.getTags();
		return getTagsByPost(keys);
	}
	
	public List<BlogTagWrapper> getTagsWrapper(BlogPost post) {
		List<BlogTag> tags = getTagsByPost(post);
		List<BlogTag> allTags = tagDao.listTags();
		
		List<BlogTagWrapper> tagWrapperList = new ArrayList<BlogTagWrapper>();
		
		for (BlogTag tag : allTags) {
			BlogTagWrapper tagWrapper = new BlogTagWrapper(tag.getId(), false, tag.getTag());
			tagWrapperList.add(tagWrapper);
		}
		
		for (int i = 0; i < tagWrapperList.size(); i++) {
			BlogTagWrapper tagWrapper = tagWrapperList.get(i);
			for (int j = 0; j < tags.size(); j++) {
				BlogTag tag = tags.get(j);
				if (tagWrapper.getTag().equals(tag.getTag())) {
					tagWrapper.setSelected(true);
				}
			}
		}
		
		return tagWrapperList;
		
	}
	
	public void rebuildBlogPopularity() {
		if (!popularBlogs.isEmpty()) {
			popularBlogs.clear();
		}
		
		List<BlogPost> posts = postDao.getAllPosts();
		for (BlogPost post : posts) {
			BlogPopularity bp = new BlogPopularity();
			bp.setBlogId(post.getId());
			bp.setCommentsSize(post.getComments().size());
			bp.setTitle(post.getTitle());
			
			popularBlogs.add(bp);
		}
		Collections.sort(popularBlogs);
	}
	
	public List<BlogPopularity> getPopularBlogs(int to) {
		if (popularBlogs != null && popularBlogs.size() >= to) {
			return popularBlogs.subList(0, to);
		}
		
		return popularBlogs;
		
	}

}

